package com.drg.center.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.drg.center.dao.*;
import com.drg.center.entity.*;
import com.drg.center.entity.enums.CaseTypeEnum;
import com.drg.center.entity.param.CaseMonitorPageDTO;
import com.drg.center.entity.param.CaseOutMonitorPageDTO;
import com.drg.center.entity.result.*;
import com.drg.center.service.CaseMonitorService;
import com.drg.center.service.StatisticsFromEsService;
import com.guaike.core.entity.result.PageEntity;
import com.guaike.core.entity.result.Result;
import com.guaike.core.utils.ListUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class CaseMonitorServiceImpl implements CaseMonitorService {

    private final DrgPatientCaseDAO drgPatientCaseDAO;
    private final DrgPatientCaseOutDAO drgPatientCaseOutDAO;
    private final DrgPatientCaseDiagnosisDAO drgPatientCaseDiagnosisDAO;
    private final DrgPatientCaseOperationDAO drgPatientCaseOperationDAO;
    private final DrgPatientCasePersonInfoDAO drgPatientCasePersonInfoDAO;
    private final DrgPatientCaseCostDAO drgPatientCaseCostDAO;
    private final DictDrgDAO dictDrgDAO;
    private final DrgPatientCaseAdviceDAO drgPatientCaseAdviceDAO;
    private final StatisticsFromEsService statisticsFromEsService;

    @Override
    public Result<CaseMonitorStatVO> inHospitalStat(CaseMonitorPageDTO param) {
        CaseMonitorStatVO vo = new CaseMonitorStatVO();
        long count = drgPatientCaseDAO.count();
        vo.setTotalCase((int) count);
        long overspendCase = drgPatientCaseDAO.count(new LambdaQueryWrapper<DrgPatientCasePO>().eq(DrgPatientCasePO::getOverCost, Boolean.TRUE));
        long highCase = drgPatientCaseDAO.count(new LambdaQueryWrapper<DrgPatientCasePO>().eq(DrgPatientCasePO::getCaseType, 2));
        long lowCase = drgPatientCaseDAO.count(new LambdaQueryWrapper<DrgPatientCasePO>().eq(DrgPatientCasePO::getCaseType, 1));
        long problemCase = drgPatientCaseDAO.count(new LambdaQueryWrapper<DrgPatientCasePO>().eq(DrgPatientCasePO::getProblemCase, Boolean.TRUE));
        long warnCase = drgPatientCaseDAO.count(new LambdaQueryWrapper<DrgPatientCasePO>().eq(DrgPatientCasePO::getWarnCase, Boolean.TRUE));
        vo.setOverspendCase((int) overspendCase);
        vo.setHighCase((int) highCase);
        vo.setLowCase((int) lowCase);
        vo.setProblemCase((int) problemCase);
        vo.setWarnCase((int) warnCase);
//        return Result.success().data(statisticsFromEsService.getCaseMonitorStat(param)).build();
        return Result.success().data(vo).build();
    }


    @Override
    public Result<PageEntity<CaseMonitorPageVO>> inHospitalPage(CaseMonitorPageDTO param) {
        int start = (param.getPageIndex() - 1) * param.getPageSize();
        PageEntity<CaseMonitorPageVO> result = new PageEntity<>();
        long total = drgPatientCaseDAO.findPageCount(param);
        if (total == 0) {
            result.setTotal(total);
            result.setList(new ArrayList<>());
            return Result.success().data(result).build();
        }
        List<CaseMonitorPageVO> vos = drgPatientCaseDAO.findPageList(start, param);
        vos.forEach(vo -> {
            DrgPatientCaseDiagnosisPO diagnosisPO = drgPatientCaseDiagnosisDAO.findMainOne(vo.getCaseCode());
            DrgPatientCaseOperationPO operationPO = drgPatientCaseOperationDAO.findMainOne(vo.getCaseCode());
            vo.setDiagnosisName(diagnosisPO.getDiagnosisName());
            if (Objects.nonNull(operationPO)) {
                vo.setOperationName(operationPO.getOperationName());
            }
            vo.setInpatientDays((int) (ChronoUnit.DAYS.between(LocalDateTime.now(), vo.getInHospitalDate()) + 1));
        });
        result.setTotal(total);
        result.setList(vos);
        return Result.success().data(result).build();
    }

    @Override
    public Result<CaseMonitorOutStatVO> outHospitalStat(CaseOutMonitorPageDTO param) {
        CaseMonitorOutStatVO vo = new CaseMonitorOutStatVO();
        long totalCase = drgPatientCaseOutDAO.outHospitalTotalCase(param);
        vo.setTotalCase((int) totalCase);
        BigDecimal totalCost = drgPatientCaseOutDAO.outHospitalTotalCost(param, "total_cost");
        BigDecimal drgCostStandard = drgPatientCaseOutDAO.outHospitalTotalCost(param, "drg_cost_standard");
        vo.setExpectedSurplus(totalCost.subtract(drgCostStandard));
        return Result.success().data(vo).build();
    }

    @Override
    public Result<PageEntity<CaseOutMonitorPageVO>> outHospitalPage(CaseOutMonitorPageDTO param) {
        int start = (param.getPageIndex() - 1) * param.getPageSize();
        PageEntity<CaseOutMonitorPageVO> result = new PageEntity<>();
        long total = drgPatientCaseOutDAO.findOutPageCount(param);
        if (total == 0) {
            result.setTotal(total);
            result.setList(new ArrayList<>());
            return Result.success().data(result).build();
        }
        List<CaseOutMonitorPageVO> vos = drgPatientCaseOutDAO.findOutPageList(start, param);
        vos.forEach(vo -> {
            DrgPatientCaseDiagnosisPO diagnosisPO = drgPatientCaseDiagnosisDAO.findMainOne(vo.getCaseCode());
            DrgPatientCaseOperationPO operationPO = drgPatientCaseOperationDAO.findMainOne(vo.getCaseCode());
            vo.setDiagnosisName(diagnosisPO.getDiagnosisName());
            vo.setOperationName(operationPO.getOperationName());
        });
        result.setTotal(total);
        result.setList(vos);
        return Result.success().data(result).build();
    }

    @Override
    public Result<CaseMonitorVO> caseDetail(Integer type, String caseCode) {
        CaseMonitorVO vo = new CaseMonitorVO();
        if (CaseTypeEnum.inHospital.getCode().equals(type)) {
            DrgPatientCasePO casePO = drgPatientCaseDAO.findOne(DrgPatientCasePO::getCaseCode, caseCode);
            if (Objects.isNull(casePO)) {
                return Result.failure().message("病例不存在").build();
            }
            vo.setDepartName(casePO.getDepartName());
            vo.setBedCode(casePO.getBedCode());
            vo.setDoctorName(casePO.getDoctorName());
            vo.setInHospitalDate(casePO.getInHospitalDate());
            vo.setInpatientDays((int) (ChronoUnit.DAYS.between(LocalDateTime.now(), casePO.getInHospitalDate()) + 1));
            vo.setTotalCost(casePO.getTotalCost());
            vo.setDrgName(casePO.getChsDrgName());
            vo.setDrgCostStandard(casePO.getDrgCostStandard());
            vo.setCaseType(casePO.getCaseType());
            vo.setReferencePoints(randomRate(70, 100).toPlainString());
            DictDrgPO drgPO = dictDrgDAO.findOne(DictDrgPO::getDrgCode, casePO.getChsDrgCode());
            if (Objects.nonNull(drgPO)) {
                vo.setIsBase(drgPO.getIsBaseDisease());
                vo.setRatio(drgPO.getDrgRate().toPlainString());
                vo.setWeight(drgPO.getDrgWeight().toPlainString());
            }
            vo.setExpectedSurplus(casePO.getTotalCost().subtract(Objects.nonNull(casePO.getDrgCostStandard()) ? casePO.getDrgCostStandard() : new BigDecimal(0)));
        } else {
            DrgPatientCaseOutPO casePO = drgPatientCaseOutDAO.findOne(DrgPatientCaseOutPO::getCaseCode, caseCode);
            if (Objects.isNull(casePO)) {
                return Result.failure().message("病例不存在").build();
            }
            vo.setDepartName(casePO.getDepartName());
            vo.setBedCode(casePO.getBedCode());
            vo.setDoctorName(casePO.getDoctorName());
            vo.setInHospitalDate(casePO.getInHospitalDate());
            vo.setInpatientDays(casePO.getInpatientDays());
            vo.setTotalCost(casePO.getTotalCost());
            vo.setDrgName(casePO.getChsDrgName());
            vo.setDrgCostStandard(casePO.getDrgCostStandard());
            vo.setCaseType(casePO.getCaseType());
            vo.setReferencePoints(randomRate(70, 100).toPlainString());
            DictDrgPO drgPO = dictDrgDAO.findOne(DictDrgPO::getDrgCode, casePO.getChsDrgCode());
            if (Objects.nonNull(drgPO)) {
                vo.setIsBase(drgPO.getIsBaseDisease());
                vo.setRatio(drgPO.getDrgRate().toPlainString());
                vo.setWeight(drgPO.getDrgWeight().toPlainString());
            }
            vo.setExpectedSurplus(casePO.getTotalCost().subtract(Objects.nonNull(casePO.getDrgCostStandard()) ? casePO.getDrgCostStandard() : new BigDecimal(0)));
        }
        DrgPatientCasePersonInfoPO personInfoPO = drgPatientCasePersonInfoDAO.findOne(DrgPatientCasePersonInfoPO::getCaseCode, caseCode);
        BeanUtils.copyProperties(personInfoPO, vo);
        DrgPatientCaseDiagnosisPO diagnosisPO = drgPatientCaseDiagnosisDAO.findMainOne(caseCode);
        List<DrgPatientCaseDiagnosisPO> pos = drgPatientCaseDiagnosisDAO.findSecondList(caseCode);
        String secondDiagnosisName = pos.stream().map(DrgPatientCaseDiagnosisPO::getDiagnosisName).collect(Collectors.joining("/"));
        vo.setDiagnosisName(diagnosisPO.getDiagnosisName());
        vo.setSecondDiagnosisName(secondDiagnosisName);
        List<DrgPatientCaseDiagnosisPO> diagnosisPOS = drgPatientCaseDiagnosisDAO.findList(DrgPatientCaseDiagnosisPO::getCaseCode, caseCode, DrgPatientCaseDiagnosisPO::getId, Boolean.TRUE);
        List<CaseMonitorDiagnosisVO> diagnosisVOS = ListUtil.copyList(diagnosisPOS, CaseMonitorDiagnosisVO.class);
        vo.setDiagnosisVOS(diagnosisVOS);
        List<DrgPatientCaseOperationPO> operationPOS = drgPatientCaseOperationDAO.findList(DrgPatientCaseOperationPO::getCaseCode, caseCode, DrgPatientCaseOperationPO::getId, Boolean.TRUE);
        List<CaseMonitorOperationVO> operationVOS = ListUtil.copyList(operationPOS, CaseMonitorOperationVO.class);
        vo.setOperationVOS(operationVOS);
        List<DrgPatientCaseCostPO> costPOS = drgPatientCaseCostDAO.findList(DrgPatientCaseCostPO::getCaseCode, caseCode, DrgPatientCaseCostPO::getId, Boolean.TRUE);
        List<CaseMonitorCostVO> costVOS = ListUtil.copyList(costPOS, CaseMonitorCostVO.class);
        vo.setCostVOS(costVOS);
        List<DrgPatientCaseAdvicePO> advicePOS = drgPatientCaseAdviceDAO.findList(DrgPatientCaseAdvicePO::getCaseCode, caseCode, DrgPatientCaseAdvicePO::getId, Boolean.TRUE);
        List<CaseAdviceVO> adviceVOS = ListUtil.copyList(advicePOS, CaseAdviceVO.class);
        vo.setAdviceVOS(adviceVOS);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<List<DrgVO>> searchDRG(String search) {
        List<DictDrgPO> pos = dictDrgDAO.searchDRG(search);
        List<DrgVO> vos = ListUtil.copyList(pos, DrgVO.class);
        return Result.success().data(vos).build();
    }

    private static BigDecimal randomRate(double min, double max) {
        return BigDecimal.valueOf(RandomUtil.randomDouble(min, max, 2, RoundingMode.HALF_UP));
    }
}
